package com.zyj.spring.factory.support;

import com.zyj.spring.factory.ListableBeanFactory;
import com.zyj.spring.ioc.BeanDefinition;
import com.zyj.spring.registry.BeanDefinitionRegistry;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通过BeanDefinitionRegistry接口去暴露DefaultListableBeanFactory，其实是符合最少认知原则
 * <p>
 * 通过实现BeanDefinitionRegistry接口，额外拥有了操作BeanDefinition的能力
 * <p>
 * 通过实现ListableBeanFactory接口，拥有了批量操作spring中bean的能力
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry, ListableBeanFactory {

    //存储spring容器中所有从xml文件中解析出来的的BeanDefinition
    private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();

    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        return this.beanDefinitions.get(beanName);
    }

    /**
     * 获取spring容器中所有的BeanDefinition
     *
     * @return
     */
    @Override
    public List<BeanDefinition> getBeanDefinitions() {
        List<BeanDefinition> beanDefinitionList = new ArrayList<>();
        // beanDefinitions.values()获取map beanDefinitions中的所有值，组成一个集合Collection返回
        for (BeanDefinition bd : beanDefinitions.values()) {
            beanDefinitionList.add(bd);
        }
        return beanDefinitionList;
    }

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition bd) {
        this.beanDefinitions.put(beanName, bd);
    }

    /**
     * 根据类型获取批量获取beans
     * 将spring容器中type类型及其子类型返回
     *
     * @param type 父类型
     * @param <T>
     * @return
     */
    @Override
    public <T> List<T> getBeansByType(Class type) {
        List<T> results = new ArrayList<>();

        List<BeanDefinition> beanDefinitions = getBeanDefinitions();
        for (BeanDefinition bd : beanDefinitions) {
            // 容器内当前类的类型
            Class<?> clazzType = bd.getClazzType();

            //A.isAssignableFrom(B) 确定一个类(B)是不是继承来自于另一个父类(A)
            //判断当前的Class对象所表示的类，是不是参数中传递的Class对象所表示的类的父类，超接口，或者是相同的类型。是则返回true，否则返回false。
            //如果clazzType是type类型的子类子接口或者是相同的类型，则判断为true，将该bd所对应的bean添加进集合并返回
            if (type.isAssignableFrom(clazzType)) {
                //此处调用getBean方法，根据beanName从spring容器中获取bean，如果容器的一级缓存中有beanName所对应的bean，则直接获取，否则将执行bean的实例化、属性注入和初始化三部曲
                results.add((T) getBean(bd.getBeanName()));
            }
        }
        return results;
    }

    @Override
    public List<String> getBeanNamesByType(Class type) {
        return null;
    }
}
